package com.xb.loan.usercenter.account.impl;

import com.xb.loan.account.service.IPointService;
import com.xb.loan.account.service.bean.PointBillVO;
import com.xb.loan.account.service.bean.PointInfoVO;
import com.xb.loan.account.service.constant.AccountConst;
import com.xb.loan.account.service.exception.IAccountServiceException;
import com.xb.loan.log.exception.BizException;
import com.xb.loan.log.exception.ErrorCodeManager;
import com.xb.loan.usercenter.account.common.VerifySet;
import com.xb.loan.usercenter.account.dao.PointBillDao;
import com.xb.loan.usercenter.account.dao.PointInfoDao;
import com.xb.loan.usercenter.account.dao.bean.PointBill;
import com.xb.loan.usercenter.account.dao.bean.PointInfo;
import com.xb.loan.usercenter.service.user.IUserService;
import com.xb.loan.usercenter.service.user.bean.UserInfoVO;
import com.xb.loan.util.cache.redis.comm.FormatOperation;
import com.xb.loan.util.common.ObjectOperation;
import com.xb.loan.util.log.DefaultLoggerFacotry;
import com.xb.loan.util.log.LogFormatUtil;
import com.xb.loan.util.mybatis.MyTransactional;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 
 * 北京掌中彩信息科技有限公司源代码，版权归北京掌中彩信息科技有限公司所有。
 * 
 * 项目名称 : common-biz 
 * 创建日期 : 2015年9月9日 
 * 类 描 述 : 用户积分账户服务 
 * 修改历史 : 
 * 	1. [2015年9月9日]创建文件  by zhangyi
 */
@Service("pointService")
public class PointServiceImpl implements IPointService, IAccountServiceException {

	private static Logger logger = DefaultLoggerFacotry.getLogger(PointServiceImpl.class);

	@Autowired
	private PointInfoDao pointInfoDao;

	@Autowired
	private PointBillDao pointBillDao;

	@Autowired(required = false)
	private IUserService userService;

	@Autowired
	// ① 注入上下文
	private ApplicationContext context;

	private PointServiceImpl proxySelf; // ② 表示代理对象，不是目标对象

	@PostConstruct
	// ③ 初始化方法
	private void setSelf() {
		// 从上下文获取代理对象（如果通过proxtSelf=this是不对的，this是目标对象）
		// 此种方法不适合于prototype Bean，因为每次getBean返回一个新的Bean
		proxySelf = (PointServiceImpl) context.getBean(IPointService.class);
	}

	@Override
	public int createPointInfo(PointInfoVO pivo) throws BizException {
		if (pivo == null || StringUtils.isEmpty(pivo.getAccountId())) {
			logger.warn(inputParameterIsWrong.getMessage(), inputParameterIsWrong);
			throw inputParameterIsWrong;
		}

		pivo.setStatus(AccountConst.AccountStatus_NONACTIVATED);

		PointInfo ap = ObjectOperation.convertByClasses(pivo, PointInfo.class);
		int intNum = pointInfoDao.insert(ap);

		return intNum;
	}

	@Override
	public PointInfoVO queryPointInfoById(String accountId) throws BizException {
		PointInfo pointInfo = pointInfoDao.queryPointInfo(accountId);
		PointInfoVO pointInfoVO = ObjectOperation.convertByClasses(pointInfo, PointInfoVO.class);
		return pointInfoVO;
	}
	
	@Override
	public PointInfoVO queryPointInfoByUserId(String userId) throws BizException {
		UserInfoVO userInfo = userService.queryUserInfoById(userId);
		VerifySet.verifyUserInfoVO(userInfo);

		return queryPointInfoById(userInfo.getAccountId());
	}

	@Override
	public List<PointBillVO> queryPointBill(String userId, Integer feeType, Integer billType, String startDate,
                                            String endDate, int pageNum, int numPerPage) throws BizException {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("userId", userId);
		map.put("feeType", feeType);
		map.put("billType", billType);
		map.put("startDate", startDate);
		map.put("endDate", endDate);
		map.put("pageNum", pageNum);
		map.put("numPerPage", numPerPage);

		List<PointBill> list = pointBillDao.queryPointBill(map);

		List<PointBillVO> listResult = ObjectOperation.convertByClassesList(list, PointBillVO.class);

		return listResult;
	}

	@Override
	public int queryPointBillCount(String userId, Integer feeType, Integer billType, String startDate, String endDate)
			throws BizException {

		Map<String, Object> map = new HashMap<String, Object>();
		map.put("userId", userId);
		map.put("feeType", feeType);
		map.put("billType", billType);
		map.put("startDate", startDate);
		map.put("endDate", endDate);

		int intNum = pointBillDao.queryPointBillCount(map);

		return intNum;
	}

	@Override
	public int updatePointInfo(String accountId, String partnerId, Integer status) throws BizException {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("accountId", accountId);
		params.put("partnerId", partnerId);
		params.put("status", status);

		return pointInfoDao.updatePointInfo(params);
	}

	@Override
	public void addPoint(String foreignId, UserInfoVO userInfoVO, int point, int billType,
                         String accountPeriod) throws BizException {
		PointInfo accountPoint = new PointInfo();
		accountPoint.setAccountId(userInfoVO.getAccountId());
		accountPoint.setMoney(point);

		PointBill apBill = createAccountPointBill(userInfoVO, billType, foreignId, accountPeriod);
		apBill.setBillIncome(point);
		proxySelf.addPointTransaction(userInfoVO, accountPoint, apBill);

		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "point_add", foreignId, userInfoVO.getUserId(), point, billType}));

	}

	/**
	 * 
	 * 添加积分事务
	 * 
	 * @param userInfo 用户对象
	 * @param accountPoint 账户积分对象
	 * @param accountPointBill 账户积分详细对象
	 * @return 2015年9月9日 by wuqinglong
	 */
	@MyTransactional
	protected void addPointTransaction(UserInfoVO userInfo, PointInfo accountPoint, PointBill accountPointBill) {
		// 获取积分账户信息
		PointInfo pointInfo = pointInfoDao.queryPointInfo(userInfo.getAccountId());
		// 更新用户帐号积分
		pointInfoDao.addPoint(accountPoint);
		// 设置积分账户原有积分
		accountPointBill.setLastMoney(pointInfo.getMoney());
		// 设置积分账户当前积分
		accountPointBill.setCurMoney(pointInfo.getMoney() + accountPoint.getMoney());
		
		pointBillDao.insert(accountPointBill);
	}

	@Override
	public void deductPoint(String foreignId, UserInfoVO userInfoVO, int point, int billType,
                            String accountPeriod) throws BizException {
		PointInfo accountPoint = new PointInfo();
		accountPoint.setAccountId(userInfoVO.getAccountId());
		accountPoint.setMoney(point);

		PointBill apBill = createAccountPointBill(userInfoVO, billType, foreignId, accountPeriod);
		apBill.setBillExpend(point);

		proxySelf.deductPointTransaction(userInfoVO, accountPoint, apBill);
		
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "point_deduct", foreignId, userInfoVO.getUserId(), point, billType}));
	}

	/**
	 * 扣除积分事务
	 * @param userInfo 用户对象
	 * @param accountPoint 账户积分对象
	 * @param accountPointBill 账户积分详细对象
	 * @return 2015年9月9日 by wuqinglong
	 * @throws BizException
	 */
	@MyTransactional
	protected void deductPointTransaction(UserInfoVO userInfo, PointInfo accountPoint, PointBill accountPointBill)
			throws BizException {
		// 获取更新后的账户余额
		PointInfo pointInfo = pointInfoDao.queryPointInfo(userInfo.getAccountId());
		int length = pointInfoDao.deductPoint(accountPoint);
		if (length < 1)
			throw IAccountServiceException.noEnoughMoney;
		
		// 设置积分账户原有积分
		accountPointBill.setLastMoney(pointInfo.getMoney());
		// 设置积分账户当前积分
		accountPointBill.setCurMoney(pointInfo.getMoney() - accountPoint.getMoney());
		
		pointBillDao.insert(accountPointBill);
	}

	/**
	 * 创建积分操作日志
	 * 
	 * @param userInfo 用户对象
	 * @param billType 记账类型
	 * @param forigenId 订单编码
	 * @param accoutPeriod 账期
	 * @return 返回积分操作日志记录
	 * @throws BizException 2015年9月9日 by wuqinglong
	 */
	protected PointBill createAccountPointBill(UserInfoVO userInfo, int billType, String forigenId,
			String accoutPeriod) throws BizException {
		PointBill apBill = new PointBill();
		apBill.setBillId(FormatOperation.assemblySeq(AccountConst.PriKey_Name, AccountConst.PriKey_Length));
		apBill.setUserId(userInfo.getUserId());
		apBill.setAccountId(userInfo.getAccountId());
		apBill.setPartnerId(userInfo.getPartnerId());
		apBill.setFeeType(AccountConst.FeeType_Default);
		apBill.setBillType(billType);
		apBill.setForigenId(forigenId);
		apBill.setAccoutPeriod(accoutPeriod);
		return apBill;
	}

	/**
	 * 
	 * 验证积分是否为正值
	 * 
	 * @param point 积分值
	 * @throws BizException 2015年9月9日 by wuqinglong
	 */
	protected void verifyDeductPoint(String foreignId, UserInfoVO userInfoVO, int point, int feeType, int billType)
			throws BizException {
		if (point <= 0) {
			logger.info(LogFormatUtil.getFormatTemplate("module", "foreignId", "point", "msg"), new Object[] { "point",
					foreignId, point, ErrorCodeManager.getErrorMsg(moneyNotPositive.getKey()) });
			throw moneyNotPositive;
		}

		PointInfo accountPoint = pointInfoDao.queryPointInfo(userInfoVO.getAccountId());
		if (accountPoint == null) {
			logger.info(LogFormatUtil.getFormatTemplate("module", "userId", "msg"), new Object[] { "point",
				userInfoVO.getUserId(), ErrorCodeManager.getErrorMsg(accountNotExsit.getKey()) });
			throw accountNotExsit;
		}
		if (accountPoint.getStatus() != AccountConst.AccountStatus_Normal) {
			logger.info(LogFormatUtil.getFormatTemplate("module", "userId", "msg"), new Object[] { "point",
				userInfoVO.getUserId(), ErrorCodeManager.getErrorMsg(accountNotNormal.getKey()) });
			throw accountNotNormal;
		}
	}

	@Override
	public void flushes(String userId, String foreignId, int billType) throws BizException {
		if(billType != AccountConst.BillType_Encash || billType != AccountConst.BillType_Purchase_Lottery){
			logger.error(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "billType", "msg"},
					new Object[]{"account", foreignId, billType, IAccountServiceException.invalidFlushesType.getMessage()}));
			throw IAccountServiceException.invalidFlushesType;
		}
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("foreignId", foreignId);
		params.put("billType", billType);
		params.put("isFlushes", AccountConst.Flushes_No);
		
		List<PointBill> bills = pointBillDao.queryPointBill(params);
		if(bills == null || bills.size() <= 0)
			return;
		
		PointBill target = bills.get(0);
		Map<String, Object> billParams = new HashMap<String, Object>();
		billParams.put("billId", target.getBillId());
		billParams.put("isFlushes", AccountConst.Flushes_Yes);
		
		Map<String, Object> flushesParams = new HashMap<String, Object>();
		flushesParams.put("accountId", target.getAccountId());
		flushesParams.put("money", target.getBillExpend());
		
		flushesTransaction(billParams, flushesParams);
		
	}

	private void flushesTransaction(Map<String, Object> billParams,
			Map<String, Object> flushesParams) {
		pointBillDao.flushes(billParams);
		pointInfoDao.flushes(flushesParams);
	}

}
